#!/usr/bin/python3
# -*- coding: utf-8 -*-

from os import environ, makedirs
from os.path import dirname, abspath, join as joinpath
from logging import basicConfig, StreamHandler, DEBUG
from arrow import now
from shutil import rmtree
from sys import stdout
from unittest import TestCase

from ikanda import create_app
from ikanda.models import db
from ikanda.core.envnames import *
from ikanda.core.callbacks import DebugCallback
from ikanda.core.command import Environment

_CWD = dirname(abspath(__file__))

basicConfig(
    format='%(asctime)s [%(levelname)-7s] %(name)s (%(pathname)s:%(lineno)d) - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    handlers=(StreamHandler(stream=stdout),),
    level=DEBUG
)


class TestBaseCase(TestCase):
    """测试用例的公共基类。"""
    __slots__ = ('__callback',)

    @staticmethod
    def cwd() -> str:
        """ 获取测试环境的工作目录。
        即`testcase`模块所在的目录。

        :return: 测试环境的工作目录。
        """
        return _CWD

    def environment(self):
        """ 构造环境变量集合。

        :return: 默认的环境变量集合。
        """
        return Environment({
            JOB_WORKING_DIRECTORY: self.cwd(),
            JOB_TIMESTAMP: now(),
        })

    @property
    def callback(self):
        """获取用于调试的回调接口。

        :return: 用于调试的回调接口。
        """
        return self.__callback

    @classmethod
    def setUpClass(cls):
        from logging import basicConfig, DEBUG, INFO

        # 初始化日志。
        if environ.get('PYTHONDEBUG'):
            basicConfig(level=DEBUG)
        else:
            basicConfig(level=INFO)

    def setUp(self):
        # 初始化回调
        self.__callback = DebugCallback()

        # 删除临时目录。
        tmpdir = joinpath(self.cwd(), 'tmp')
        rmtree(joinpath(self.cwd(), 'tmp'), ignore_errors=True)
        makedirs(tmpdir)

    def tearDown(self):
        # 关闭回调
        self.__callback.close()
        self.__callback = None


class TestAppBaseCase(TestBaseCase):
    """加入`app`上下文的测试用例公共基类"""
    __slots__ = ('__context', '__client',)

    def setUp(self):
        super().setUp()
        app = create_app(instance_path=self.cwd())
        self.__context = app.test_request_context()
        self.__context.push()
        self.__client = app.test_client()
        db.create_all()

    def tearDown(self):
        db.drop_all()
        self.context.pop()

    @property
    def db(self):
        return db

    @property
    def context(self):
        return self.__context

    @property
    def client(self):
        return self.__client
